import { BehaviorSubject, Observable, Observer } from 'rxjs'
import { IOption, IFormItem, FormItemType } from '@shared/interfaces/common'
import { numScale, compareTwoCurrencies } from 'app/utils/helpers'
import { ALPChannel } from '@shared/interfaces/acquirer'
import { Validators, FormControl, ValidationErrors, ValidatorFn, FormGroup } from '@angular/forms'
import {
  AlipayPartnerIDMaxLength,
  AlipayPartnerIDReg,
  TransactionFeeReg,
  MD5KeyMaxLength,
  MD5KeyReg,
  ChannelMerchantNameMaxLength,
  SFTPUsernameMaxLength,
  SFTPUsernameReg,
  SFTPPasswordMaxLength,
  SFTPPasswordReg,
  SFTPPathMaxLength,
  SFTPPathReg,
  ALPAppIdMaxLength,
  ALPAppIdReg,
} from 'app/utils/contraints'

const isSupportAuthHidden$ = new BehaviorSubject<boolean>(true)
const isSettlementCurrHidden$ = new BehaviorSubject<boolean>(true)
const isSignKeyHidden$ = new BehaviorSubject<boolean>(true)
const isCurrencySpan$ = new BehaviorSubject<string>('24')
const isPaymentSpan$ = new BehaviorSubject<string>('24')
const isPreAuthSpan$ = new BehaviorSubject<string>('24')

export const genALPFormItems = (
  currencyOptions: IOption[],
  currencyCodeOptions: IOption[],
  handleChanMerIDChange,
): IFormItem[] => {
  isSupportAuthHidden$.next(true)
  isSettlementCurrHidden$.next(true)
  isSignKeyHidden$.next(true)
  return [
    {
      label: 'Alipay Partner ID',
      errTips: {
        required: '必填项',
        existed: '该渠道已存在',
        maxLength: '最长不超过 64 位',
        pattern: '格式错误，只支持数字',
      },
      formControlName: 'chanMerID',
      change: handleChanMerIDChange,
    },
    {
      label: 'Is Support Alipay Currency Conversion',
      errTips: {
        required: 'at least payment or pre-auth is on',
      },
      asyncSpan: isCurrencySpan$,
      errTip: '',
      formControlName: 'isSupportSettleCurr',
      type: FormItemType.SWITCH,
      change: (isSupport: boolean) => {
        isSettlementCurrHidden$.next(!isSupport)
        isCurrencySpan$.next(isSupport ? '12' : '24')
      },
    },
    {
      label: 'Settlement Currency',
      errTips: {
        required: '必填项',
      },
      formControlName: 'settleCurrency',
      type: FormItemType.CURRENCY_SELECT,
      currencyType: 'string',
      multiple: 'default',
      allowClear: true,
      compareFn: compareTwoCurrencies,
      asyncHidden: isSettlementCurrHidden$,
    },
    {
      label: 'Is Support Payment',
      errTips: {
        required: 'at least payment or pre-auth is on',
      },
      asyncSpan: isPaymentSpan$,
      errTip: '',
      formControlName: 'isSupportPayment',
      type: FormItemType.SWITCH,
      change: (isSupport: boolean) => {
        isSignKeyHidden$.next(!isSupport)
        isPaymentSpan$.next(isSupport ? '12' : '24')
      },
    },
    {
      label: 'MD5 Key',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过64',
        pattern: '格式错误：只支持数字字母',
      },
      formControlName: 'signKey',
      asyncHidden: isSignKeyHidden$,
    },
    {
      label: 'Is Support Pre-authorization',
      errTips: {
        required: 'at least payment or pre-auth is on',
      },
      formControlName: 'isSupportPreAuth',
      asyncSpan: isPreAuthSpan$,
      type: FormItemType.SWITCH,
      change: (isSupport: boolean) => {
        isSupportAuthHidden$.next(!isSupport)
        isPreAuthSpan$.next(isSupport ? '12' : '24')
      },
    },
    {
      label: 'alpAppID',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过64',
        pattern: '格式错误:只支持数字字母',
      },
      formControlName: 'appID',
      asyncHidden: isSupportAuthHidden$,
    },
    {
      label: 'Alipay RSA Public Key',
      errTip: '',
      type: FormItemType.FILE,
      formControlName: 'publicKey',
      asyncHidden: isSupportAuthHidden$,
    },
    {
      label: 'RSA Private Key',
      errTip: '',
      type: FormItemType.FILE,
      formControlName: 'privateKeyArray',
      asyncHidden: isSupportAuthHidden$,
    },
    {
      label: 'Channel Merchant Name',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过 50 位',
      },
      formControlName: 'chanMerName',
    },
    {
      label: 'Transaction Currency',
      errTips: {
        required: '必填项',
      },
      formControlName: 'currencies',
      type: FormItemType.CURRENCY_SELECT,
      multiple: 'multiple',
      allowClear: true,
      compareFn: compareTwoCurrencies,
      options: currencyOptions,
    },
    {
      label: 'Transaction Fee',
      errTips: {
        required: '必填项',
        pattern: '格式不正确，最多只支持四位小数,且不可为负数',
      },
      errTip: 'Transaction Fee 只能在0-10%之间',
      formControlName: 'fee',
      type: FormItemType.INPUTGROUP,
      addAfter: '%',
      inputType: 'number',
    },
    {
      label: 'Settlement Type',
      errTips: {
        required: '必填项',
      },
      formControlName: 'settType',
      type: FormItemType.RADIO,
      options: [
        {
          label: 'settlement',
          value: 0,
        },
        {
          label: 'transaction',
          value: 1,
        }
      ]
    },
    {
      label: 'SFTP username',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过64位',
        pattern: '格式错误：只支持数字字母',
      },
      formControlName: 'sftpUsername',
    },
    {
      label: 'SFTP password',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过64位',
        pattern: '格式错误：只支持数字字母',
      },
      inputType: 'password',
      formControlName: 'sftpPassword',
    },
    {
      label: 'SFTP Path',
      errTips: {
        required: '必填项',
        maxLength: '最长不超过64位',
        pattern: '格式错误：只支持数字字母和/',
      },
      formControlName: 'sftpFilePath',
    },
  ]
}

export const genALPValidateRules = (channel: ALPChannel): { [key: string]: any } => {
  const preAuthAsyncValidator = getValidator(isSupportAuthHidden$, [
    Validators.required,
    Validators.maxLength(ALPAppIdMaxLength),
    Validators.pattern(ALPAppIdReg),
  ])
  const publicKeyAsyncValidator = getValidator(isSupportAuthHidden$, [Validators.required])
  const privateKeyArrayAsyncValidator = getValidator(isSupportAuthHidden$, [Validators.required])
  const settleCurrencyValidator = getValidator(isSettlementCurrHidden$, [Validators.required])
  const signKeyValidator = getValidator(isSignKeyHidden$, [
    Validators.required,
    Validators.maxLength(MD5KeyMaxLength),
    Validators.pattern(MD5KeyReg),
  ])

  return {
    id: [null, []],
    chanCode: [channel && channel.chanCode, [Validators.required]],
    chanMerID: [
      channel && channel.chanMerID,
      [Validators.required, Validators.maxLength(AlipayPartnerIDMaxLength), Validators.pattern(AlipayPartnerIDReg)],
    ],
    currencies: [channel && channel.currencies, [Validators.required]],
    fee: [
      channel && numScale(channel.fee, 2),
      [Validators.required, Validators.min(0), Validators.max(10), Validators.pattern(TransactionFeeReg)],
    ],
    isSupportPayment: [(channel && channel.signKey) ? true : false, [], []],
    signKey: [channel && channel.signKey, [], [signKeyValidator]],
    chanMerName: [
      channel && channel.chanMerName,
      [Validators.required, Validators.maxLength(ChannelMerchantNameMaxLength)],
    ],
    isSupportSettleCurr: [(channel && channel.settleCurrency) ? true : false, []],
    settleCurrency: [channel && (channel as ALPChannel).settleCurrency, [], [settleCurrencyValidator]],
    settType: [ channel && (channel as ALPChannel).settType || 0, [Validators.required] ],
    sftpUsername: [
      channel && (channel as ALPChannel).sftp.username,
      [Validators.required, Validators.maxLength(SFTPUsernameMaxLength), Validators.pattern(SFTPUsernameReg)],
    ],
    sftpPassword: [
      channel && (channel as ALPChannel).sftp.password,
      [Validators.required, Validators.maxLength(SFTPPasswordMaxLength), Validators.pattern(SFTPPasswordReg)],
    ],
    sftpFilePath: [
      channel && (channel as ALPChannel).sftp.filePath,
      [Validators.required, Validators.maxLength(SFTPPathMaxLength), Validators.pattern(SFTPPathReg)],
    ],
    isSupportPreAuth: [channel && (channel as ALPChannel).isSupportPreAuth, []],
    appID: [channel && channel.appID, [], [preAuthAsyncValidator]],
    publicKey: [channel && channel.publicKey, [], [publicKeyAsyncValidator]],
    privateKeyArray: [channel && channel.privateKeyArray, [], [privateKeyArrayAsyncValidator]],
    isLoaded: [ channel && channel.isLoaded],
  }
}

export const genALPAdditionalValidateRules = (channel: ALPChannel) => {
  return {
    validator: modeAtLeastOne(),
  }
}

const modeAtLeastOne = () => {
  return (formGroup: FormGroup) => {
    const isPaymentCtrl = formGroup.controls['isSupportPayment']
    const isPreAuthCtrl = formGroup.controls['isSupportPreAuth']
    if (!isPaymentCtrl.value && !isPreAuthCtrl.value) {
      isPaymentCtrl.setErrors({ required: true })
      isPreAuthCtrl.setErrors({ required: true })
    } else {
      isPaymentCtrl.setErrors(null)
      isPreAuthCtrl.setErrors(null)
    }
  }
}

const getValidator = (hidden$, validators: ValidatorFn[]) => (control: FormControl) => {
  return new Observable((observer: Observer<ValidationErrors | null>) => {
    control.setValidators(validators)
    hidden$.subscribe(isHidden => {
      if (isHidden) {
        control.clearValidators()
        observer.next(null)
        observer.complete()
        return
      }
      const valid = control.valid
      if (!valid) {
        observer.next(control.errors)
      }
      observer.complete()
    })
  })
}
